package com.qk.manangement.aspect;

import com.qk.common.context.UserContext;
import com.qk.common.response.Result;
import com.qk.entity.pojo.OperateLog;
import com.qk.entity.pojo.User;
import com.qk.manangement.mapper.OperateLogMapper;
import com.qk.manangement.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@Slf4j
@Aspect
@Component
public class LogInfoAspect {

    @Autowired
    private OperateLogMapper operateLogMapper;
    @Autowired
    private UserMapper userMapper;

    // 切点为 com.qk.manangement.controller包下的所有方法
    @Around("execution(* com.qk.manangement.controller.CustomerController.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        // 获取方法名称
        String methodName = joinPoint.getSignature().getName();
        // 获取方法所在类名
        String className = joinPoint.getTarget().getClass().getName();

        // 将参数转换为指定格式
        String formattedArgs = formatArgs(args);

        Integer userId = UserContext.getUserId();

        //方法开始时间
        long startTime = System.currentTimeMillis();

        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable e) {
            result = Result.error(e.getMessage());
            throw e; // 重新抛出异常，让上层正确处理
        } finally {
            //方法结束时间
            long endTime = System.currentTimeMillis();

            // 异步保存操作日志，避免影响主业务流程性能
            saveOperateLog(joinPoint, formattedArgs, result, startTime, endTime,userId);
        }

        return result;
    }

    /**
     * 异步保存操作日志
     */
    @Async
    public void saveOperateLog(ProceedingJoinPoint joinPoint, String methodParams,
                                  Object result, long startTime, long endTime, Integer userId) {
        try {

            OperateLog log = OperateLog.builder()
                    .operateUserId(userId)
                    .operateTime(new Date())
                    .className(joinPoint.getTarget().getClass().getName())
                    .methodName(joinPoint.getSignature().getName())
                    .methodParams(methodParams)
                    .returnValue(result != null ? result.toString() : "")
                    // 耗时单位ms
                    .costTime((int) (endTime - startTime))
                    .build();

            // 保存到数据库
            operateLogMapper.insert(log);
        } catch (Exception e) {
            // 日志保存失败不应影响主流程
            // 可以记录到系统日志中
            log.error("保存操作日志失败：" + e.getMessage());
        }
    }


    /**
     * 将参数数组转换为指定格式字符串
     *
     * @param args 参数数组
     * @return 格式化后的字符串
     */
    private String formatArgs(Object[] args) {
        if (args == null || args.length == 0) {
            return "[]";
        }

        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < args.length; i++) {
            if (i > 0) {
                sb.append(", ");
            }
            sb.append(formatObject(args[i]));
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * 将单个对象转换为指定格式字符串
     *
     * @param obj 对象
     * @return 格式化后的字符串
     */
    private String formatObject(Object obj) {
        if (obj == null) {
            return "null";
        }

        Class<?> clazz = obj.getClass();
        // 如果是基本类型或String类型，直接返回值
        if (clazz.isPrimitive() || obj instanceof String || obj instanceof Number || obj instanceof Boolean || obj instanceof Character) {
            return obj.toString();
        }

        // 如果是日期类型，格式化日期
        if (obj instanceof Date) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
            return sdf.format(obj);
        }

        // 对于其他对象，尝试使用反射获取字段值
        StringBuilder sb = new StringBuilder();
        sb.append(clazz.getSimpleName()).append("(");
        boolean first = true;
        for (Field field : clazz.getDeclaredFields()) {
            try {
                field.setAccessible(true);
                Object value = field.get(obj);
                if (!first) {
                    sb.append(", ");
                }
                sb.append(field.getName()).append("=");
                if (value instanceof Date) {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                    sb.append(sdf.format(value));
                } else {
                    sb.append(value);
                }
                first = false;
            } catch (IllegalAccessException e) {
                // 忽略无法访问的字段
            }
        }
        sb.append(")");
        return sb.toString();
    }
}
